/*
	Lua control application execution 
*/

/* Kernel includes. */
#include <FreeRTOS.h>
#include "task.h"
#include "timers.h"

/* lua includes */
#include "lua/lua.h"
#include "lua/lauxlib.h"
#include "lua/lualib.h"

#include "lua_control.h"

/* Automation script body */
char auto_script_body[1024] = "";

/* Sleep function (for Lua scripts) */
static void lua_sleep(lua_State *lua_state)
{
	/* Pop number from stack - 1st argument is delay passed to sleep */
	int ms = lua_tonumber(lua_state, 1);
	vTaskDelay(ms/portTICK_RATE_MS);
}

/* Output string to console (for Lua scripts) */
static void control_echo(lua_State *lua_state)
{
	/* Pop string from stack - 1st argument is string passed to echo */
	size_t len = 0;
	const char *string = lua_tolstring(lua_state, 1, &len);
	/* Print string on console */
	if(string != NULL)
		puts(string);
}

/* Show error message (to be called after lua error) */
static void show_error(lua_State *lua)
{
	int errmsg_len;
	const char *errmsg = lua_tolstring(lua, -1, &errmsg_len);
	printf("Lua error: %s\n", errmsg);
	lua_pop(lua, 1);
}

/* Execute lua script */
static lua_State *initialize_lua()
{
	lua_State *lua;
	/* Initialize interpreter and libraries */
	lua = lua_open();
	if(lua == NULL)
		return NULL;
	if(!luaopen_string(lua))
		return NULL;
	if(!luaopen_os(lua))
		return NULL;
	if(!luaopen_math(lua))
		return NULL;
	if(!luaopen_table(lua))
		return NULL;
	/* Register function 'echo' */
	lua_pushcfunction(lua, control_echo);
    lua_setglobal(lua, "echo");
	/* Register function 'sleep' */
	lua_pushcfunction(lua, lua_sleep);
    lua_setglobal(lua, "sleep");
	return lua;
}

/* Execute lua script */
void execute_auto_script(void *pvParameters)
{
	lua_State *lua = pvParameters;

	/* Load script and execute it */
	if(luaL_loadstring(lua, auto_script_body))
	{
		show_error(lua);
		return;
	}
	if(lua_pcall(lua, 0, 0, 0))
	{
		show_error(lua);
		return;
	}
}

xTaskHandle auto_handle;
lua_State *lua;

/* Starting Lua control thread */
void start_control_thread()
{
	lua_State *lua = initialize_lua();
	if(lua == NULL)
		return;
	xTaskCreate(execute_auto_script, "auto", 500, lua, tskIDLE_PRIORITY, &auto_handle);
}

/* Stopping Lua control thread */
void stop_control_thread()
{
	if(lua == NULL)
		return;
	lua_close(lua);
	vTaskDelete(auto_handle);
}
